/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package model;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import view.MonteCarloWindow;

/**
 *
 * @author aaaz
 */
public final class MonteCarloFunction implements ViewReqInterface {

    @Override
    public void StopThread(int nBar) {
        System.out.println("STOPING THREAD");
        barThreads.get(nBar).interrupt();
    }

    private int nBar = 0;
    private List<Thread> barThreads = new ArrayList<>();

    @Override
    public void MonteCarloStandardOption(String callPutFlag, double s, double x, double t, double r, double b, double v, int nSteps, int nSimulations, MonteCarloWindow monteCarloWindow) {
        int currentBar = nBar;

        barThreads.add(new Thread(new monteThread(callPutFlag, s, x, t, r, b, v, nSteps, nSimulations, monteCarloWindow, currentBar)));
        barThreads.get(nBar).start();

        nBar++;
    }

    private class monteThread implements Runnable {

        private String callPutFlag;
        private double s, x, t, r, b, v;
        private int nSteps, nSimulations;
        private MonteCarloWindow monteCarloWindow;
        private int currentBar;

        public monteThread(String callPutFlag, double s, double x, double t, double r, double b, double v, int nSteps, int nSimulations, MonteCarloWindow monteCarloWindow, int currentBar) {
            this.callPutFlag = callPutFlag;
            this.s = s;
            this.t = t;
            this.r = r;
            this.b = b;
            this.v = v;
            this.x = x;
            this.nSteps = nSteps;
            this.nSimulations = nSimulations;
            this.monteCarloWindow = monteCarloWindow;
            this.currentBar = currentBar;
        }

        @Override
        public void run() {

            System.out.println("thread");
            monteCarloWindow.addBar(currentBar);
            monteCarloWindow.setInfoText(currentBar, "F: " + callPutFlag + " S: " + s + " X: " + x + " T: " + t + " R: " + r + " B: " + b + " V: " + v + " Steps: " + nSteps + " Simulations: " + nSimulations);
            long startTime = System.currentTimeMillis();
            long runningMillisecods = 0;
            long predictTime = 0;
            long currentTime = 0;
            int minutesR, secondsR;
            int minutesL, secondsL;
            double percentaje;
            double partialValue = 0;
            double returnValue = 0;
            double dt = 0;
            double st = 0;
            double sum = 0;
            double drift = 0;
            double vSqrdt = 0;
            int z = 0;
            dt = t / nSteps;
            drift = ((b - Math.pow(v, 2) / 2) * dt);
            vSqrdt = v * Math.sqrt(dt);
            if ("c".equals(callPutFlag)) {
                z = 1;
            } else if ("p".equals(callPutFlag)) {
                z = -1;
            }

            for (int i = 0; i <= nSimulations; i++) {
                st = s;
                for (int j = 0; j <= nSteps; j++) {
                    st = st * Math.exp(drift + vSqrdt * new Random().nextGaussian());
                }
                sum = sum + Math.max(z * (st - x), 0);
                if (i % 500 == 0.0) {
                    partialValue = Math.exp(-r * t) * (sum / i);
                    monteCarloWindow.setReslutValue(currentBar, partialValue);
                    percentaje = i * 100.0 / nSimulations;
                    monteCarloWindow.setPBarValue(currentBar, (int) (Math.ceil(percentaje)));
                    currentTime = System.currentTimeMillis();
                    runningMillisecods = currentTime - startTime;
                    predictTime = ((nSimulations - i) * runningMillisecods) / (i + 1);
                    minutesR = (int) TimeUnit.MILLISECONDS.toMinutes(runningMillisecods) % 60;
                    secondsR = (int) TimeUnit.MILLISECONDS.toSeconds(runningMillisecods) % 60;
                    minutesL = (int) TimeUnit.MILLISECONDS.toMinutes(predictTime) % 60;
                   secondsL = (int) TimeUnit.MILLISECONDS.toSeconds(predictTime) % 60;

                    monteCarloWindow.setPBarText(currentBar, String.format("%03.3f", percentaje) + " % Running: " + TimeUnit.MILLISECONDS.toHours(runningMillisecods) + ":" + minutesR + ":" + secondsR + " Left: " + TimeUnit.MILLISECONDS.toHours(predictTime) + ":" + minutesL + ":" + secondsL);
                    if (Thread.interrupted()) {
                        monteCarloWindow.setBarStatus(currentBar, 2);
                        return;

                    };
                }

            }
            returnValue = Math.exp(-r * t) * (sum / nSimulations);
            monteCarloWindow.setReslutValue(currentBar, returnValue);
            monteCarloWindow.setPBarValue(currentBar, 100);
            monteCarloWindow.setBarStatus(currentBar, 1);
            currentTime = System.currentTimeMillis();
            runningMillisecods = currentTime - startTime;
            monteCarloWindow.setPBarText(currentBar, "100 % Running: " + TimeUnit.MILLISECONDS.toHours(runningMillisecods) + ":" + TimeUnit.MILLISECONDS.toMinutes(runningMillisecods) + ":" + TimeUnit.MILLISECONDS.toSeconds(runningMillisecods));
            System.out.println("BAR: " + currentBar);
            System.out.println("VALUE: " + returnValue);
            System.out.println("MILLISECONDS: " + runningMillisecods);

        }
    }
}
